#include "application.h"
#include <iostream>
#include <gtkglmm.h>
#include <GL/gl.h>
#include <GL/glu.h>

namespace moogle
{
  static void print_gl_attrib(const Glib::RefPtr<const Gdk::GL::Config>& glconfig,
			      const char* attrib_str,
			      int attrib,
			      bool is_boolean);

  static void examine_gl_attrib(const Glib::RefPtr<const Gdk::GL::Config>& glconfig);

  application::application(int argc, char** argv)
    : main(argc, argv)
  {
    Gtk::GL::init(argc, argv);

    //
    // Query OpenGL extension version.
    //

    int major, minor;
    Gdk::GL::query_version(major, minor);
    std::cout << "OpenGL extension version - " << major << "." << minor << std::endl;

    //
    // Configure OpenGL-capable visual.
    //

    Glib::RefPtr<Gdk::GL::Config> glconfig;

    // Try double-buffered visual
    glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB    |
				       Gdk::GL::MODE_DEPTH  |
				       Gdk::GL::MODE_DOUBLE);

    if (!glconfig)
    {
      std::cerr << "Cannot find the double-buffered visual\n" << "Trying single-buffered visual" << std::endl;

      // Try single-buffered visual
      glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB | Gdk::GL::MODE_DEPTH);
      
      if (!glconfig)
      {
        std::cerr << "Cannot find any OpenGL-capable visual" << std::endl;
        std::exit(1);
      }
    }

    // print frame buffer attributes.
    examine_gl_attrib(glconfig);

    //
    // Instantiate and run the application.
    //
    wnd = new main_window(glconfig);
  }

  application::~application()
  {
    delete wnd;
  }

  int application::run()
  {
    Gtk::Main::run(*wnd);
    return 0;
  }

  //
  // Print a configuration attribute.
  //
  void print_gl_attrib(const Glib::RefPtr<const Gdk::GL::Config>& glconfig,
				     const char* attrib_str,
				     int attrib,
				     bool is_boolean)
  {
    int value;
    
    if (glconfig->get_attrib(attrib, value))
    {
      std::cout << attrib_str << " = ";
      if (is_boolean)
        std::cout << (value == true ? "true" : "false") << std::endl;
      else
        std::cout << value << std::endl;
    }
    else
    {
      std::cout << "*** Cannot get " << attrib_str << " attribute value\n";
    }
  }

  //
  // Print configuration attributes.
  //
  void examine_gl_attrib(const Glib::RefPtr<const Gdk::GL::Config>& glconfig)
  {
    std::cout << "\nOpenGL visual configurations :\n\n";

    std::cout << "glconfig->is_rgba() = "
	      << (glconfig->is_rgba() ? "true" : "false")
	      << std::endl;
    std::cout << "glconfig->is_double_buffered() = "
	      << (glconfig->is_double_buffered() ? "true" : "false")
	      << std::endl;
    std::cout << "glconfig->is_stereo() = "
	      << (glconfig->is_stereo() ? "true" : "false")
	      << std::endl;
    std::cout << "glconfig->has_alpha() = "
	      << (glconfig->has_alpha() ? "true" : "false")
	      << std::endl;
    std::cout << "glconfig->has_depth_buffer() = "
	      << (glconfig->has_depth_buffer() ? "true" : "false")
	      << std::endl;
    std::cout << "glconfig->has_stencil_buffer() = "
	      << (glconfig->has_stencil_buffer() ? "true" : "false")
	      << std::endl;
    std::cout << "glconfig->has_accum_buffer() = "
	      << (glconfig->has_accum_buffer() ? "true" : "false")
	      << std::endl;

    std::cout << std::endl;

    print_gl_attrib(glconfig, "Gdk::GL::USE_GL",           Gdk::GL::USE_GL,           true);
    print_gl_attrib(glconfig, "Gdk::GL::BUFFER_SIZE",      Gdk::GL::BUFFER_SIZE,      false);
    print_gl_attrib(glconfig, "Gdk::GL::LEVEL",            Gdk::GL::LEVEL,            false);
    print_gl_attrib(glconfig, "Gdk::GL::RGBA",             Gdk::GL::RGBA,             true);
    print_gl_attrib(glconfig, "Gdk::GL::DOUBLEBUFFER",     Gdk::GL::DOUBLEBUFFER,     true);
    print_gl_attrib(glconfig, "Gdk::GL::STEREO",           Gdk::GL::STEREO,           true);
    print_gl_attrib(glconfig, "Gdk::GL::AUX_BUFFERS",      Gdk::GL::AUX_BUFFERS,      false);
    print_gl_attrib(glconfig, "Gdk::GL::RED_SIZE",         Gdk::GL::RED_SIZE,         false);
    print_gl_attrib(glconfig, "Gdk::GL::GREEN_SIZE",       Gdk::GL::GREEN_SIZE,       false);
    print_gl_attrib(glconfig, "Gdk::GL::BLUE_SIZE",        Gdk::GL::BLUE_SIZE,        false);
    print_gl_attrib(glconfig, "Gdk::GL::ALPHA_SIZE",       Gdk::GL::ALPHA_SIZE,       false);
    print_gl_attrib(glconfig, "Gdk::GL::DEPTH_SIZE",       Gdk::GL::DEPTH_SIZE,       false);
    print_gl_attrib(glconfig, "Gdk::GL::STENCIL_SIZE",     Gdk::GL::STENCIL_SIZE,     false);
    print_gl_attrib(glconfig, "Gdk::GL::ACCUM_RED_SIZE",   Gdk::GL::ACCUM_RED_SIZE,   false);
    print_gl_attrib(glconfig, "Gdk::GL::ACCUM_GREEN_SIZE", Gdk::GL::ACCUM_GREEN_SIZE, false);
    print_gl_attrib(glconfig, "Gdk::GL::ACCUM_BLUE_SIZE",  Gdk::GL::ACCUM_BLUE_SIZE,  false);
    print_gl_attrib(glconfig, "Gdk::GL::ACCUM_ALPHA_SIZE", Gdk::GL::ACCUM_ALPHA_SIZE, false);

    std::cout << std::endl;
  }
}
